#region Summary

// 
// Owner : JackieHan 
// 
// Solution : WebShopApi 
// 
// Project : Jackie.Utility
// 
// File : WebUtils.cs
// 
// CopyRight : Copyright © 2010-2011 Skomart Corporation, All Rights Reserved 
// 
// Summary : 关于Web的一些公用方法
// 
// History : 
//			2011-04-14 22:28:28	    Create 
// 

#endregion

#region Using

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using Jackie.Utility.CustomExtension;

#endregion

namespace Jackie.Utility.Web
{
    /// <summary> 
    /// 关于Web的一些公用方法
    /// </summary>
    public class WebUtils
    {
        private int timeOut = 120000;

        /// <summary>
        /// 获取或设置请求响应的超时时间
        /// </summary>
        public int TimeOut
        {
            get { return timeOut; }
            set { timeOut = value; }
        }

        /// <summary>
        /// 执行HTTP POST请求
        /// </summary>
        /// <param name="url">Url</param>
        /// <param name="parameters">POST参数</param>
        /// <param name="headerParams">Http头参数</param>
        /// <returns></returns>
        public string DoPost(string url, IDictionary<string, string> parameters, IDictionary<string, string> headerParams)
        {
            var request = (headerParams == null || headerParams.Count == 0)
                              ? GetWebRequest(url, "POST")
                              : GetWebRequest(url, "POST", headerParams);
            request.ContentType = "application/x-www-form-urlencoded;charset=utf-8";

            var postData = Encoding.UTF8.GetBytes(BuildQuery(parameters));
            var requestStream = request.GetRequestStream();
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();

            var response = (HttpWebResponse)request.GetResponse();
            var encoding = Encoding.GetEncoding(response.CharacterSet);
            return GetResponseAsString(response, encoding);
        }


        /// <summary>
        /// 执行带文件上传的HTTP POST请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="textParameters">请求文本参数</param>
        /// <param name="fileParameters">请求文件参数</param>
        /// <param name="headerParams">Http头参数</param>
        /// <returns></returns>
        public string DoPost(string url, IDictionary<string, string> textParameters, IDictionary<string, FileItem> fileParameters,
            IDictionary<string, string> headerParams)
        {
            if (fileParameters == null || fileParameters.Count == 0)
                return DoPost(url, textParameters, headerParams);

            var boundary = DateTime.Now.Ticks.ToString("X");

            var request = (headerParams == null || headerParams.Count == 0)
                              ? GetWebRequest(url, "POST")
                              : GetWebRequest(url, "POST", headerParams);
            request.ContentType = "multipart/form-data;charset=uft-8;boundary=" + boundary;

            var requestStream = request.GetRequestStream();
            var itemBoundaryBytes = Encoding.UTF8.GetBytes(string.Format("\r\n--{0}\r\n", boundary));
            var endBoundaryBytes = Encoding.UTF8.GetBytes(string.Format("\r\n--{0}--\r\n", boundary));

            var textTemplate = "Content-Disposition:form-data;name=\"{0}\"\r\nContent-Type:text/plain\r\n\r\n{1}";
            var textParamsEnumerator = textParameters.GetEnumerator();
            while (textParamsEnumerator.MoveNext())
            {
                var textEntry = string.Format(textTemplate, textParamsEnumerator.Current.Key,
                                              textParamsEnumerator.Current.Value);
                var itemBytes = Encoding.UTF8.GetBytes(textEntry);
                requestStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                requestStream.Write(itemBytes, 0, itemBytes.Length);
            }

            var fileTemplate = "Content-Disposition:form-data;name=\"{0}\";filename=\"{1}\"\r\nContent-Type:{2}\r\n\r\n";
            var fileParamsEnumerator = fileParameters.GetEnumerator();
            while (fileParamsEnumerator.MoveNext())
            {
                var key = fileParamsEnumerator.Current.Key;
                var fileItem = fileParamsEnumerator.Current.Value;
                var fileEntry = string.Format(fileTemplate, key, fileItem.GetFileName(), fileItem.GetMimeType());
                var itemBytes = Encoding.UTF8.GetBytes(fileEntry);
                requestStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                requestStream.Write(itemBytes, 0, itemBytes.Length);

                var fileBytes = fileItem.GetContent();
                requestStream.Write(fileBytes, 0, fileBytes.Length);
            }

            requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
            requestStream.Close();

            var response = (HttpWebResponse)request.GetResponse();
            var encoding = Encoding.GetEncoding(response.CharacterSet);
            return GetResponseAsString(response, encoding);
        }

        /// <summary>
        /// 执行HTTP Get请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数</param>
        /// <param name="headerParams">Http头参数</param>
        /// <returns></returns>
        public string DoGet(string url, IDictionary<string, string> parameters, IDictionary<string, string> headerParams)
        {
            if (parameters != null && parameters.Count > 0)
            {
                if (url.Contains("?"))
                    url += "&" + BuildQuery(parameters);
                else
                    url += "?" + BuildQuery(parameters);
            }

#if DEBUG
            Console.WriteLine(url);
#endif

            var request = (headerParams == null || headerParams.Count == 0)
                              ? GetWebRequest(url, "GET")
                              : GetWebRequest(url, "GET", headerParams);
            request.ContentType = "application/x-www-form-urlencoded;charset=utf-8";

            var response = (HttpWebResponse)request.GetResponse();
            var encoding = Encoding.GetEncoding(response.CharacterSet);
            return GetResponseAsString(response, encoding);
        }

        private string GetResponseAsString(HttpWebResponse response, Encoding encoding)
        {
            var resultBuilder = new StringBuilder();
            Stream stream = null;
            StreamReader reader = null;

            try
            {
                stream = response.GetResponseStream();
                reader = new StreamReader(stream, encoding);
                char[] buffer = new char[256];
                int readBytes = 0;
                while ((readBytes = reader.Read(buffer, 0, buffer.Length)) > 0)
                {
                    resultBuilder.Append(buffer, 0, readBytes);
                }
            }
            finally
            {
                if (reader != null) reader.Close();
                if (stream != null) stream.Close();
                if (response != null) response.Close();
            }
            return resultBuilder.ToString();
        }

        private string BuildQuery(IDictionary<string, string> parameters)
        {
            var queryBuilder = new StringBuilder();
            var hasParam = false;

            var dem = parameters.GetEnumerator();
            while (dem.MoveNext())
            {
                var name = dem.Current.Key;
                var value = dem.Current.Value;
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
                {
                    if (hasParam)
                        queryBuilder.Append("&");
                    queryBuilder.Append(name);
                    queryBuilder.Append("=");
                    queryBuilder.Append(HttpUtility.UrlEncode(value));
                    hasParam = true;
                }
            }

            return queryBuilder.ToString();
        }

        private HttpWebRequest GetWebRequest(string url, string method)
        {
            var req = (HttpWebRequest)WebRequest.Create(url);
            req.KeepAlive = true;
            req.Timeout = TimeOut;
            req.Method = method;
            return req;
        }

        private HttpWebRequest GetWebRequest(string url, string method, IDictionary<string, string> headerParams)
        {
            var request = GetWebRequest(url, method);
            var headers = new WebHeaderCollection();
            headerParams.ForEach(item => headers.Add(item.Key, item.Value));
            request.Headers = headers;
            return request;
        }
    }
}